package com.kerrykidz.common;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

import com.rdp.util.config.SpringUtil;

/**
 * 我们的主键千万不能使用自增列或者自己手写一些逻辑生成PK <br>
 * 不然在数据同步的时候可能会导致主键冲突 <br>
 * 所有的开发人员的主键生成都用此类生成
 * 
 * @Description 主键生成工具
 * @author QUINN
 * @date 2014年8月6日下午9:14:17
 */
public class PrimaryKeyGenerator {

	/**
	 * 当天的日期字符串，如2014年8月8日该变量值为140808
	 */
	private static String TODAY = getTodayTime(new Date());

	public final static long ONE_DAY = 0x5265c00;

	private final static String UPDATE_SQL = "UPDATE SYS_SEQ SET INC_NO = ? WHERE BUSI_NAME= ? AND CRE_DATE=?";
	private final static String INSERT_SQL = "INSERT INTO SYS_SEQ (BUSI_NAME,CRE_DATE,INC_NO) VALUES(?,?,1)";
	private final static String SELECT_SQL = "SELECT INC_NO FROM SYS_SEQ WHERE BUSI_NAME= ? AND CRE_DATE = ?";

	/**
	 * 
	 * @Description 获取唯一主键
	 * @param type
	 *            当前业务类型
	 * @param storeName
	 *            门店名称 内容必须为大写字母简写,比如天津门店:TJ,北京门店:BJ
	 * @return
	 * @author QUINN
	 * @date 2014年8月6日下午7:40:00
	 */
	public static String getPrimaryKey(BusinessType type, String storeName) {

		if (StringUtils.isBlank(storeName) || !storeName.matches("[a-zA-Z\\d]+"))
			try {
				throw new PrimaryKeyException("门店简写不合法");
			} catch (PrimaryKeyException e) {
				e.printStackTrace();
			}

		if (type == null)
			try {
				throw new PrimaryKeyException("业务类型不能为空");
			} catch (PrimaryKeyException e) {
				e.printStackTrace();
			}

		synchronized (type) {
			String btype = type.toString();
			JdbcTemplate jdbcTemplate = SpringUtil.getBeanByType(JdbcTemplate.class);
			String today = TODAY;
			String no = getPrimaryKeyNo(jdbcTemplate, btype, today);
			return storeName + btype + today + no;
		}
	}

	/**
	 * 如果在页面没有列表的主键，用该方法生成
	 * 
	 * @Desc 获取随机主键
	 * @author QUINN
	 * @date 2014年9月17日上午10:48:28
	 * @return
	 */
	public static String getRandomPrimaryKey() {
		return UUID.randomUUID().toString().replace("-", "");
	}

	private static String getPrimaryKeyNo(JdbcTemplate jdbcTemplate, String btype, String today) {
		Integer no;
		try {
			Map<String, Object> result = jdbcTemplate.queryForMap(PrimaryKeyGenerator.SELECT_SQL, btype, today);
			no = (Integer) result.get("INC_NO");
		} catch (EmptyResultDataAccessException e) {
			no = null;
		}

		String pkno;
		if (no == null) {
			pkno = "0001";
			doInsert(jdbcTemplate, btype, today);
		} else {
			no++;
			pkno = no.toString();
			while (pkno.length() < 4) {
				pkno = "0" + pkno;
			}
			doUpdate(jdbcTemplate, btype, no, today);
		}
		return pkno;
	}

	private static void doUpdate(JdbcTemplate jdbcTemplate, String btype, Integer no, String today) {
		jdbcTemplate.update(UPDATE_SQL, no, btype, today);
	}

	private static void doInsert(JdbcTemplate jdbcTemplate, String btype, String today) {
		jdbcTemplate.update(INSERT_SQL, btype, today);
	}

	private static String getTodayTime(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
		return sdf.format(date);
	}

	static {
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {

			@Override
			public void run() {
				TODAY = getTodayTime(new Date());
			}
		}, getDelay(), ONE_DAY);
	}

	private static long getDelay() {
		Calendar c = Calendar.getInstance();
		c.add(Calendar.DAY_OF_MONTH, 1);
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		return c.getTime().getTime() - System.currentTimeMillis();
	}

	/**
	 * 请开发人员注意，如果你要增加的业务类型在页面有列表查询，才在这里增加一个枚举，否则没必要用这个
	 * 
	 * @Description 业务类型
	 * @author QUINN
	 * @date 2014年8月6日下午7:29:31
	 */
	public static enum BusinessType {

		XS// 销售订单
		, CG// 采购订单
		, FK// 付款单
		, SP// 商品
		, YY// 预约
		, RK// 库存stock（入库单号）
		, CK// 库存stock（出库库单号）
		, PD// 库存盘点
		, TZ// 库存调整
		, HY// 会员
		, GY// 供应商
		, QJ // 请假
		, CZ// 充值
		, PA// LOC_PARTY_INOUT '派对出入场表'
		, PE// LOC_PER_INOUT '个人出入场表'
		, TH // 退货单
		, CX //
		, KF// 客户服务
		, KC// 课程签到表
		, XY// 课程记录表
		, DX// 短信
		, DJ//定价
		, PC;//批次号
	}
}
